The i386 architecture uses four kinds of instruction operands:
Each type of operand corresponds to an addressing mode. Register operands specify that the value stored in the named register is to be used by the operator. Immediate operands are constant values specified in assembler code. Direct memory operands are the memory location of labels, or the value of a named register treated as an address. Indirect memory operands are calculated at run time from the contents of registers and optional constant values.
A register operand is given simply as the name of a register. It can be any of the identifiers beginning with `%' listed above; for example, %eax . When an operator calls for a register operand of a particular size, the operand is listed as r8 , r16 , or r32 .
Immediate operands are specified as numeric values preceded by a dollar sign (`$'). They are decimal by default, but can be marked as hexadecimal by beginning the number itself with `0x'. Simple calculations are allowed if grouped in parentheses. Finally, an immediate operand can be given as a label, in which case its value is the address of that label. Here are some examples:
$100
$0x5fec4
$(10*6) # calculated by the assembler
$begloop
A reference to an undefined label is allowed, but that reference must be resolved at link time.
Direct memory operands are references to labels in assembler source. They act as static references to a single location in memory relative to a specific segment, and are resolved at link time. Here's an example:
.data
var: .byte 0 # declare a byte-size variable labelled "var"
.text
.
.
.
movb %al,var # move the low byte of the AX register into the
# memory location specified by "var"
By default, direct memory operands use the %ds segment register. This can be overridden by prefixing the operands with the segment register desired and a colon:
movb %es:%al,var # move the low byte of the AX register into the
# memory location in the segment given by %es
# and "var"
Note that the segment override applies only to the memory operands in an instruction; "var" is affected, but not %al . The string instructions, which take two memory operands, use the segment override for both. A less common way of indicating a segment is to prefix the operator itself:
es/movb %al,%var # same as above
Indirect memory operands are calculated from the contents of registers at run time. An indirect memory operand can contain a base register, and index register, a scale, and a displacement. The most general form is:
displacement ( base_register,index_register,scale )
displacement is an immediate value. The base and index registers may be any 32-bit general register names, except that %esp can't be used as an index register. scale must be 1, 2, 4, or 8; no other values are allowed. The displacement and scale can be omitted, but at least one register must be specified. Also, if items from the end are omitted, the preceding commas can also be omitted, but the comma following an omitted item must remain:
10(%eax,%edx)
(%eax)
12(,%ecx,2)
12(,%ecx)
The value of an indirect memory operand is the memory location given by the contents of the register, relative to a segment's base address. The segment register used is %ss when the base register is %ebp or %esp , and %ds for all other base registers. For example:
movl (%eax),%edx # default segment register here is %ds
The above assembler instruction moves 32 bits from the address given by %eax into the %edx register. The address %eax is relative to the %ds segment register. A different segment register from the default can be specified by prefixing the operand with the segment register name and a colon (`:'):
movl %es:(%eax),%edx
A segment override can also be specified as an operator prefix:
es/movl (%eax),%edx